open Lexing

type pos = int * int    (* Line number and column *)
type t = string * pos * pos

let line_of_pos (l,_) = l
let col_of_pos (_,c) = c
let mk_pos line col = (line, col)

let file_of_range (f,_,_) = f
let start_of_range (_,s,_) = s
let end_of_range (_,_,e) = e
let mk_range f s e = (f,s,e)
let valid_pos (l,c) = l >= 0 && c >=0

let merge_range ((f,s1,e1) as r1) ((f',s2,e2) as r2) =
  if f <> f' then failwith @@ Printf.sprintf "merge_range called on different files: %s and %s" f f'
  else
  if not (valid_pos s1) then r2 else
  if not (valid_pos s2) then r1 else
  mk_range f (min s1 s2) (max e1 e2)

let string_of_range (f,(sl,sc),(el,ec)) =
  Printf.sprintf "%s:[%d.%d-%d.%d]" f sl sc el ec

let ml_string_of_range (f,(sl,sc),(el,ec)) =
  Printf.sprintf "(%s, (%d, %d), (%d, %d))" f sl sc el ec

let norange = ("__internal", (0,0), (0,0))

(* Creates a Range.pos from the Lexing.position data *)
let pos_of_lexpos (p:position) : pos =
  mk_pos (p.pos_lnum) (p.pos_cnum - p.pos_bol)

let mk_lex_range (p1:position) (p2:position) : t =
  mk_range p1.pos_fname (pos_of_lexpos p1) (pos_of_lexpos p2)

(* Expose the lexer state as a Range.t value *)
let lex_range lexbuf : t = 
  mk_lex_range (lexeme_start_p lexbuf) (lexeme_end_p lexbuf)
    
